package com.kancy.springcloudconfig.action;

import com.kancy.springcloudconfig.Settings;
import com.kancy.springcloudconfig.action.model.AlgorithmData;
import com.kancy.springcloudconfig.action.model.RefreshObject;
import com.kancy.springcloudconfig.exception.AlertException;
import com.kancy.springcloudconfig.exception.UnsupportedFunctionException;
import com.kancy.springcloudconfig.factory.BeanFactory;
import com.kancy.springcloudconfig.factory.MainFrameBeanNameResolver;
import com.kancy.springcloudconfig.util.CommonUtil;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.security.InvalidKeyException;
import java.util.Objects;

/**
 * <p>
 * AbstractAlgorithmAction
 * </p>
 *
 * @author: kancy
 * @date: 2019/10/26 15:01
 **/
public abstract class AbstractAlgorithmAction implements AlgorithmAction{
    private static MainFrameBeanNameResolver mainFrameBeanNameResolver = new MainFrameBeanNameResolver();

    @Override
    public final void execute(ActionEvent e) {
        AlgorithmData algorithmData = null;
        try {
            // 1.检查数据
            algorithmData = initAlgorithmData();
            checkAlgorithmData(algorithmData);
            // 2.判断是加密还是解密
            if (algorithmData.isEncrypt()){

                String cipherText = null;
                String plainText = algorithmData.getPlainText();

                if (Settings.isBatchMode()){

                    String line_split_char = "\n";
                    if (plainText.indexOf("\r\n") > 0){
                        line_split_char = "\r\n";
                    }

                    String[] arrays = plainText.split(line_split_char);
                    StringBuilder builder = new StringBuilder();
                    for (String plainTextRow : arrays) {
                        if (plainTextRow != null && plainTextRow.length() > 0){
                            algorithmData.setPlainText(plainTextRow);
                            try {
                                builder.append(encrypt(algorithmData)).append(line_split_char);
                            } catch (Exception ex) {
                                builder.append("<<加密失败>>").append(line_split_char);
                            }
                        }else{
                            if (arrays.length > 1){
                                builder.append(line_split_char);
                            }
                        }
                    }
                    cipherText = builder.toString();
                    if (cipherText.endsWith(line_split_char)){
                        cipherText = cipherText.substring(0, cipherText.length() - line_split_char.length());
                    }
                }else{
                    cipherText = encrypt(algorithmData);
                }

                algorithmData.setPlainText(plainText);
                algorithmData.setCipherText(cipherText);
                algorithmData.getCipherTextArea().setText(cipherText);
                System.out.println(String.format("明文：%s , 密文：%s" , algorithmData.getPlainText(), algorithmData.getCipherText()));
            }else{
                String plainText = null;
                String cipherText = algorithmData.getCipherText();
                if (Settings.isBatchMode()){

                    String line_split_char = "\n";
                    if (cipherText.indexOf("\r\n") > 0){
                        line_split_char = "\r\n";
                    }

                    String[] arrays = cipherText.split(line_split_char);
                    StringBuilder builder = new StringBuilder();
                    for (String cipherTextRow : arrays) {
                        if (cipherTextRow != null && cipherTextRow.length() > 0){
                            algorithmData.setCipherText(cipherTextRow);
                            try {
                                builder.append(decrypt(algorithmData)).append(line_split_char);
                            } catch (Exception ex) {
                                builder.append("<<解密失败>>").append(line_split_char);
                            }
                        }else {
                            if (arrays.length > 1){
                                builder.append(line_split_char);
                            }
                        }
                    }
                    plainText = builder.toString();
                    if (plainText.endsWith(line_split_char)){
                        plainText = plainText.substring(0, plainText.length() - line_split_char.length());
                    }
                }else{
                    plainText = decrypt(algorithmData);
                }
                algorithmData.setCipherText(cipherText);
                algorithmData.setPlainText(plainText);
                algorithmData.getPlainTextArea().setText(plainText);
                System.out.println(String.format("密文：%s , 明文：%s" , algorithmData.getCipherText(), algorithmData.getPlainText()));
            }
        } catch (AlertException x){
            JOptionPane.showMessageDialog(null, x.getMessage());
        }  catch (UnsupportedFunctionException x){
            JOptionPane.showMessageDialog(null, x.getMessage());
        }  catch (Exception x) {
            System.err.println(x.getMessage());
            if (Objects.nonNull(algorithmData) && x.getCause() instanceof InvalidKeyException){
                int keyLen = algorithmData.getSalt().length();
                if (keyLen > 16){
                    JOptionPane.showMessageDialog(null, String.format("<html>当前JAVA版本[%s]不支持[%s]位加密密钥" +
                            "<br>" +
                            "请升级JAVA版本或者安装JCE Proxy！" +
                            "<br>" +
                            "<a href='https://www.oracle.com/java/technologies/javase-jce8-downloads.html'>安装JCE Proxy</a>" +
                            "</html>", System.getProperty("java.version"), keyLen));
                    return;
                }
            }
            JOptionPane.showMessageDialog(null, "加解密失败!");
        }
    }

    @Override
    public final void refresh() {
        update(initRefreshObject());
    }

    /**
     * 解密逻辑
     * @param data
     */
    protected abstract String decrypt(AlgorithmData data);

    /**
     * 加密逻辑
     * @param data
     */
    protected abstract String encrypt(AlgorithmData data);


    /**
     * 更新
     * @param object
     */
    protected void update(RefreshObject object){

    }

    /**
     * 检查数据
     * @param data
     */
    protected void checkAlgorithmData(AlgorithmData data) {
        assert data.getPlainTextArea() != null : "内置对象丢失";
        assert data.getCipherTextArea() != null : "内置对象丢失";

        assert data.isEncrypt() && CommonUtil.isNotEmpty(data.getPlainText()) : "加密内容不能为空！";
        assert data.isDecrypt() && CommonUtil.isNotEmpty(data.getCipherText()) : "解密内容不能为空！";
    }


    private RefreshObject initRefreshObject() {
        JPasswordField passwordObject = BeanFactory.getBean(mainFrameBeanNameResolver.beanName("passwordField"), JPasswordField.class);
        JPasswordField saltObject = BeanFactory.getBean(mainFrameBeanNameResolver.beanName("passwordFieldSalt"), JPasswordField.class);
        JLabel label1Object =  BeanFactory.getBean(mainFrameBeanNameResolver.beanName("label1"), JLabel.class);
        JLabel label2Object =  BeanFactory.getBean(mainFrameBeanNameResolver.beanName("label2"), JLabel.class);

        RefreshObject object = new RefreshObject();
        object.setLabel1Object(label1Object);
        object.setLabel2Object(label2Object);
        object.setPasswordObject(passwordObject);
        object.setSaltObject(saltObject);
        return object;
    }


    private final AlgorithmData initAlgorithmData() {
        JPasswordField passwordField = BeanFactory.getBean(mainFrameBeanNameResolver.beanName("passwordField"), JPasswordField.class);
        JPasswordField passwordFieldSalt = BeanFactory.getBean(mainFrameBeanNameResolver.beanName("passwordFieldSalt"), JPasswordField.class);
        JRadioButton jRadioButtonEncrypt = BeanFactory.getBean(mainFrameBeanNameResolver.beanName("jRadioButtonEncrypt"), JRadioButton.class);
        JTextArea cipherTextArea = BeanFactory.getBean(mainFrameBeanNameResolver.beanName("cipherTextArea"), JTextArea.class);
        JTextArea plainTextArea = BeanFactory.getBean(mainFrameBeanNameResolver.beanName("plainTextArea"), JTextArea.class);

        AlgorithmData data = new AlgorithmData();
        data.setPassword(passwordField.getText());
        data.setSalt(passwordFieldSalt.getText());
        data.setCipherTextArea(cipherTextArea);
        data.setCipherText(cipherTextArea.getText());
        data.setPlainTextArea(plainTextArea);
        data.setPlainText(plainTextArea.getText());
        data.setEncrypt(jRadioButtonEncrypt.isSelected());
        return data;
    }
}
